﻿package fab.graphics
{
	import fab.geom.Circle;
	import fab.geom.Drawer;
	import flash.display.BitmapData;
	import flash.display.DisplayObject;
	import flash.display.Graphics;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.filters.BlurFilter;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	
	import flash.display.GradientType;
	import flash.display.InterpolationMethod;
	import flash.display.SpreadMethod;	

	public class Transitions extends EventDispatcher
	{
		static public var liste:Array = new Array();
		private var mask1:Sprite;
		private var increment:Number;
		private var engine_function:Function;
		public var toRemove:DisplayObject;
		private var transObject:Object;
		private var mask2:Sprite;
		
		static public var TYPE_CIRCLEIN:String = "circle_in";
		static public var TYPE_CIRCLEOUT:String = "circle_out";
		static public var TYPE_RADAR:String = "radar";
		static public var TYPE_RADARX:String = "radarx";
		static public var TYPE_VOLETDIAGO:String = "voletdiago";
		private var running:Boolean=false;
		
		public function Transitions( type:String, toRemove:DisplayObject, transObject:Object=null ) 
		{
			trace("Transitions", type, toRemove );
			this.toRemove = toRemove;
			
			
			if ( transObject == null ) transObject = { };
			if ( transObject.centre == null ) transObject.centre = new Point( 0,0 );
			if ( transObject.vitesse == null ) transObject.vitesse = 8;
			if ( transObject.radius == null ) transObject.radius = 450;
			if ( transObject.sens == null ) transObject.sens = 1;
			if ( transObject.rectangle == null ) transObject.rectangle = new Rectangle(0,0,960,600);
			this.transObject = transObject;
			
			mask1 = new Sprite();
			mask1.graphics.beginFill(0xFF0000) ; 
			mask1.graphics.drawRect( -500, -500, 1500, 1500) ; 
			mask1.graphics.endFill()  ;
			
			if ( toRemove.parent != null ) toRemove.parent.addChild( mask1 );
			toRemove.mask = mask1;
			
			switch( type )
			{
				case TYPE_CIRCLEIN:
				mask1.filters = [ new BlurFilter(40, 40, 1) ];
				increment = transObject.radius;
				engine_function = run_circle_in;
				break;
				case TYPE_CIRCLEOUT:
				mask1.filters = [ new BlurFilter(40, 40, 1) ];
				increment = 0;
				engine_function = run_circle_out;
				break;
				case TYPE_RADAR:
				mask1.filters = [ new BlurFilter(40, 40, 1) ];
				increment = -360;
				engine_function = run_radar;
				break;		
				case TYPE_RADARX:
				mask1.filters = [ new BlurFilter(20,20, 1) ];
				increment = -360;
				engine_function = run_radarx;
				break;	
				case TYPE_VOLETDIAGO:
				mask1.filters = [ new BlurFilter(20,20, 1) ];
				increment = transObject.rectangle.width;
				engine_function = run_voletdiago;
				break;					
			}
			liste.push( this );
			
		}
		static public function hasTransitionRunning( toRemove:DisplayObject ):Boolean
		{
			for each( var t:Transitions in liste ) if ( t.toRemove == toRemove && t.running ) return true;
			return false;
		}				
		static public function removeAllTransitions():void
		{
			for each( var transition:Transitions in liste )
			{
				transition.remove();
			}
		}		
		static public function add( type:String, toRemove:DisplayObject, transObject:Object=null ):Transitions
		{
			var t:Transitions = new Transitions(type, toRemove, transObject );
			t.start();
			return t;
		}
		public function remove():void
		{
			if ( mask1 && mask1.parent != null ) 
			{
				mask1.parent.removeChild( mask1 );
				mask1.graphics.clear() ; 
			}
			
			if ( toRemove != null )
			{
				trace("REMOVE")  ;
				toRemove.removeEventListener(Event.ENTER_FRAME, engine_function);
				toRemove.mask = null;
				toRemove.cacheAsBitmap = false ; 
			}
		}		
		public function start():void
		{
			//toRemove.cacheAsBitmap = true;
			toRemove.addEventListener(Event.ENTER_FRAME, engine_function);
			running = true;
		}
		public function stop():void
		{
			if ( mask1.parent != null ) mask1.parent.removeChild( mask1 );
			toRemove.removeEventListener(Event.ENTER_FRAME, engine_function);
			toRemove.mask = null;
			toRemove.cacheAsBitmap = false ; 
			if ( transObject.onComplete is Function ) ( transObject.onComplete as Function ).apply( null, transObject.onCompleteParams );
			running = false;
		}
		
		// engines
		
		private function run_radar(e:Event):void 
		{
			mask1.graphics.clear();
			mask1.graphics.beginFill( 0x000000 );
			drawCone( mask1.graphics, transObject.centre.x, transObject.centre.y, transObject.radius, increment , 270 );
			mask1.graphics.endFill();
			toRemove.cacheAsBitmap = true; 
			if ( increment >= 0 ) stop();
			increment += transObject.vitesse;
		}
		private function run_radarx(e:Event):void 
		{
			mask1.graphics.clear();
			mask1.graphics.beginFill( 0x00FF00 );
			drawCone( mask1.graphics, transObject.centre.x, transObject.centre.y, transObject.radius, increment/2 , 270 );
			drawCone( mask1.graphics, transObject.centre.x, transObject.centre.y, transObject.radius, increment/2 , 90 );
			mask1.graphics.endFill();
			toRemove.cacheAsBitmap = true; 
			if ( increment >= 0 ) stop();
			increment += transObject.vitesse;
		}
		private function run_circle_out(e:Event):void 
		{
			mask1.graphics.clear();
			mask1.graphics.beginFill( 0x000000 );
			drawDisk( mask1.graphics, transObject.centre.x, transObject.centre.y, increment, transObject.radius );
			mask1.graphics.endFill();
			toRemove.cacheAsBitmap = true; 
			mask1.cacheAsBitmap = true; 
			if ( increment >= transObject.radius ) stop();
			increment = increment + transObject.vitesse;
		}			
		private function run_circle_in(e:Event):void 
		{
			mask1.graphics.clear();
			mask1.graphics.beginFill( 0xFF0000 );
			mask1.graphics.drawCircle( transObject.centre.x, transObject.centre.y, increment );
			mask1.graphics.endFill();
			toRemove.cacheAsBitmap = true; 
			mask1.cacheAsBitmap = true; 
			if ( increment <= 0 ) stop();
			increment = increment - transObject.vitesse;
		}	
		private function run_voletdiago(e:Event):void 
		{
			var rect:Rectangle = transObject.rectangle;
			var k:Number = increment / transObject.rectangle.width;
			mask1.graphics.clear();
			mask1.graphics.lineStyle( 1, 0xFF00FF );
			mask1.graphics.beginFill( 0xFF0000 );
			
			mask1.graphics.moveTo( rect.left, rect.top );
			mask1.graphics.lineTo( rect.left + increment, rect.top );
			mask1.graphics.lineTo( rect.left, rect.top + transObject.rectangle.height * k );
			mask1.graphics.lineTo( rect.left, rect.top );
			
			mask1.graphics.moveTo( rect.right, rect.bottom );
			mask1.graphics.lineTo( rect.right - increment, rect.bottom );
			mask1.graphics.lineTo( rect.right, rect.bottom - transObject.rectangle.height * k );
			mask1.graphics.lineTo( rect.right, rect.bottom );
			
			mask1.graphics.endFill();
			toRemove.cacheAsBitmap = true; 
			mask1.cacheAsBitmap = true; 

			if ( increment <= 0 ) stop();
			increment = increment - transObject.vitesse;
		}
		
		// statics
		
		static public function drawDisk(graphics:Graphics, sx:Number, sy:Number, radius1:Number, radius2:Number):void 
		{
			graphics.moveTo( sx + Math.cos(0) * radius1, sy + Math.sin(0) * radius1 );
			graphics.lineTo( sx + Math.cos(0) * radius2, sy + Math.sin(0) * radius2 );
			drawOneCircle( graphics, sx, sy, radius2 );
			graphics.lineTo( sx + Math.cos(0) * radius1, sy + Math.sin(0) * radius1 );
			drawOneCircle( graphics, sx, sy, radius1 );
		}
		static public function drawOneCircle(graphics:Graphics, sx:Number, sy:Number, radius:Number ):void 
		{
			var segAngle:Number;
			var angle:Number;
			var angleMid:Number;
			var numOfSegs:Number;
			var ax:Number;
			var ay:Number;
			var bx:Number;
			var by:Number;
			var cx:Number;
			var cy:Number;
			
			numOfSegs = Math.ceil(Math.abs(360) / 45);
			segAngle = 360 / numOfSegs;
			segAngle = (segAngle / 180) * Math.PI;
			angle = (0 / 180) * Math.PI;
			
			for ( var i:int = 0; i < numOfSegs; i++) 
			{
				angle += segAngle;
				angleMid = angle - (segAngle / 2);
				bx = sx + Math.cos(angle) * radius;
				by = sy + Math.sin(angle) * radius;
				cx = sx + Math.cos(angleMid) * (radius / Math.cos(segAngle / 2));
				cy = sy + Math.sin(angleMid) * (radius / Math.cos(segAngle / 2));
				graphics.curveTo(cx, cy, bx, by);
			}	
		}
		static public function drawCone(graphics:Graphics, sx:Number, sy:Number, radius:Number, arc:Number, startAngle:Number=0):void 
		{
			var segAngle:Number;
			var angle:Number;
			var angleMid:Number;
			var numOfSegs:Number;
			var ax:Number;
			var ay:Number;
			var bx:Number;
			var by:Number;
			var cx:Number;
			var cy:Number;

			// Move the pen
			graphics.moveTo(sx, sy);

			// No need to draw more than 360
			if (Math.abs(arc) > 360) 
			{
				arc = 360;
			}

			numOfSegs = Math.ceil(Math.abs(arc) / 45);
			segAngle = arc / numOfSegs;
			segAngle = (segAngle / 180) * Math.PI;
			angle = (startAngle / 180) * Math.PI;

			// Calculate the start point
			ax = sx + Math.cos(angle) * radius;
			ay = sy + Math.sin(angle) * radius;

			// Draw the first line
			graphics.lineTo(ax, ay);

			for (var i:int = 0; i < numOfSegs; i++) 
			{
				angle += segAngle;
				angleMid = angle - (segAngle / 2);
				bx = sx + Math.cos(angle) * radius;
				by = sy + Math.sin(angle) * radius;
				cx = sx + Math.cos(angleMid) * (radius / Math.cos(segAngle / 2));
				cy = sy + Math.sin(angleMid) * (radius / Math.cos(segAngle / 2));
				graphics.curveTo(cx, cy, bx, by);
			}

			// Close the wedge
			graphics.lineTo(sx, sy);
		}
		static public function drawCross( graphics:Graphics, p:Point, taille:Number=8 ):void
		{
			graphics.moveTo( p.x - taille, p.y );
			graphics.lineTo( p.x + taille, p.y );
			graphics.moveTo( p.x, p.y - taille);
			graphics.lineTo( p.x, p.y + taille);		
		}			
	}
}